package com.geek.thread.locks;

import com.geek.util.UnSafeUtil;
import lombok.extern.slf4j.Slf4j;
import sun.misc.Unsafe;

import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.locks.LockSupport;

/**
 * 自己简单实现一个重入锁ReentrantLock
 * 这里面还是有bug，当线程运行到unlock，另一个线程tryLock之间，queue里面是没有东西的，unlock并没有唤醒其他线程，之后再入队，这样所有线程就park住了——20220622
 */
@Slf4j
public class MyReentrantLock {

	ConcurrentLinkedQueue<Thread> queue = new ConcurrentLinkedQueue<>();

	private long state = 0;
	private static volatile long stateOffset = 0L;

	private final static  Unsafe unsafe = UnSafeUtil.getInstance();

	static{
		initStateOffset();
	}

	static void initStateOffset(){
		try {
			stateOffset = unsafe.objectFieldOffset(MyReentrantLock.class.getDeclaredField("state"));
		} catch (NoSuchFieldException e) {
			e.printStackTrace();
		}
	}


	public void lock(){
		Thread curThread = Thread.currentThread();
		while (true){//自旋锁
			if(tryLock()){
				log.info("某个线程获取到锁了:"+curThread.getName());
				break;
			}else{
				queue.add(curThread);
				LockSupport.park(curThread);
			}
		}
	}

	/**
	 * 尝试加锁
	 */
	private boolean tryLock(){
		Thread curThread = Thread.currentThread();
		boolean result = unsafe.compareAndSwapInt(this, stateOffset, 0, 1);
		log.info(curThread.getName()+"尝试获取锁，结果:{}, {}", result, stateOffset);
		return result;
	}

	public void unlock(){
		Thread curThread = Thread.currentThread();
		log.info("线程释放锁:"+curThread.getName());
		try {
			state = 0;
			initStateOffset();
			log.info("等待线程的数量："+queue.size());
			while (queue.size()>0){
				Thread thread = queue.remove();
				log.info("启动线程："+thread.getName());
				LockSupport.unpark(thread);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private static int total = 0;
	private static final CyclicBarrier cyclicBarrier = new CyclicBarrier(2);//用于各个线程公平抢cpu
	public static void main(String[] args) throws Exception {
		MyReentrantLock lock = new MyReentrantLock();
		for (int i = 0; i < 100; i++) {
			Thread thread = new Thread(() -> {
					try {
						for (int j = 0; j < 2; j++) {
//							cyclicBarrier.await();
							lock.lock();
							total++;
							lock.unlock();
						}
					} catch (Exception e) {
						e.printStackTrace();
					}
			});
			thread.setName("thread-"+i);
			thread.start();
		}
		Thread.sleep(1000);
		log.info("结果："+total);

	}

}
